package source

import (
	"strings"
	"math/big"
	"kumachan/standalone/util/richtext"
)


type Errors ([] *Error)
type Error struct {
	Location  Location
	Content   ErrorContent
	Depth     uint
}
type ErrorContent interface {
	DescribeError() richtext.Block
}
type LocatableErrorMessage struct {
	Location  Location
	Content   richtext.Block
}
type SerializableErrorMessage struct {
	Content    richtext.Block
	FilePath   string
	PosText    string
	PosIndex1  *big.Int
	PosIndex2  *big.Int
}

// ----------------------
func ErrorsFrom(err *Error) Errors {
	if err != nil {
		return Errors([] *Error { err })
	} else {
		return nil
	}
}
func ErrorsJoin(errs *Errors, err *Error) {
	if err != nil {
		*errs = append(*errs, err)
	}
}
func ErrorsJoinAll(errs *Errors, another Errors) {
	for _, err := range another {
		*errs = append(*errs, err)
	}
}
func (errs Errors) Message() richtext.Block {
	if len(errs) == 0 {
		panic("invalid operation")
	}
	var b richtext.Block
	for _, item := range errs {
		b.Append(item.Message())
	}
	return b
}
func (errs Errors) Error() string {
	if len(errs) == 0 {
		panic("invalid operation")
	}
	var all = make([] string, len(errs))
	for i, item := range errs {
		all[i] = item.Error()
	}
	return strings.Join(all, "\n")
}

// ----------------------
func MakeError(loc Location, content ErrorContent) *Error {
	return &Error {
		Location: loc,
		Content:  content,
	}
}
func (e *Error) IncreaseDepth() *Error {
	e.Depth += 1
	return e
}
func (e *Error) ToLocatable() LocatableErrorMessage {
	return LocatableErrorMessage {
		Location: e.Location,
		Content:  e.Content.DescribeError(),
	}
}
func (e *Error) Message() richtext.Block {
	var m = e.ToLocatable()
	return m.ToBlock()
}
func (e *Error) Error() string {
	return e.Message().RenderPlainText()
}

// ----------------------
func (msg *LocatableErrorMessage) ToBlock() richtext.Block {
	return msg.Location.FormatMessage(msg.Content)
}
func (msg *LocatableErrorMessage) ToSerializable() *SerializableErrorMessage {
	return &SerializableErrorMessage {
		Content:   msg.Content,
		FilePath:  msg.Location.File.GetPath(),
		PosText:   msg.Location.File.DescribePosition(msg.Location.Pos),
		PosIndex1: big.NewInt(int64(msg.Location.Pos.Index1)),
		PosIndex2: big.NewInt(int64(msg.Location.Pos.Index2)),
	}
}


